# -*- coding: utf-8 -*-
# kol_match.py
# Created by Hardy on 24th, Jan
# Copyright 2017 杭州网川教育科技有限公司. All rights reserved.

from querier.esquerier import ElasticSearchQuerier
import utils.utils as utils

MAX_BRANDS = 40
MAX_CATEGORY = 16
MAX_CHARACTER = 50
MINIMUM_SHOULD_MATCH = '5<85% 10<9'
CATEGORY_CUTOFF = 0.7
MAX_KEYWORDS = 100


class DarenKOLMatchWithBrandQuerier(ElasticSearchQuerier):
    def __init__(self, kol_match, brand_match):
        super(DarenKOLMatchWithBrandQuerier, self).__init__(None, None, None)
        self.kol_match = kol_match
        self.brand_match = brand_match

    def search(self, args):
        term = args.get('term', '')
        term = term if term else ''
        filters = args.get('filters', {})
        filters = filters if filters else {}
        order = args.get('order_by', utils.ORDER_OVERALL)
        order = order if order else utils.ORDER_OVERALL
        from_ = args.get('from', 0)
        from_ = from_ if from_ else 0
        size_ = args.get('size', 10)
        size_ = size_ if size_ else 10
        highlight = args.get('highlight', False)
        highlight = highlight if highlight in (True, False) else False

        kol_match_args = {
            'term': term,
            'filters': filters,
            'order_by': order,
            'from': from_,
            'size': size_,
            'highlight': highlight,
        }

        kol_result = self.kol_match.search(kol_match_args)

        keywords = kol_result.get('keywords', [])
        # ex_keywords = []
        ex_keywords = [a.get('text', '') for a in kol_result.get('ex_keywords', [])][0:10]
        keywords += ex_keywords

        brand_match_args = {
            'term': ' '.join(keywords[0:10]),
            'from': 0,
            'size': MAX_BRANDS
        }

        brand_result = self.brand_match.search(brand_match_args)

        brands = [b.get('brand', '') for b in brand_result.get('brands', [])]
        weights = [b.get('score', '') for b in brand_result.get('brands', [])]
        brands = utils.get_kv_json(brands, weights)

        kol_result['ex_brands'] = brands

        return kol_result

    def _build_query(self, args): pass

    def _build_result(self, es_result, param): pass


class DarenKOLMatchQuerier(ElasticSearchQuerier):
    def __init__(self, es, index, doc_type, nlp_service=None):
        super(DarenKOLMatchQuerier, self).__init__(es, index, doc_type)
        self.nlp_service = nlp_service

    def _build_query(self, args):
        """
        从args创建查询
        :param args:
        :return:
        """

        term = args.get('term', '')
        term = term if term else ''
        filters = args.get('filters', {})
        filters = filters if filters else {}
        order = args.get('order_by', utils.ORDER_OVERALL)
        order = order if order else utils.ORDER_OVERALL
        from_ = args.get('from', 0)
        from_ = from_ if from_ else 0
        size_ = args.get('size', 10)
        size_ = size_ if size_ else 10
        highlight = args.get('highlight', False)
        highlight = highlight if highlight in (True, False) else False

        # 处理查询文本
        term2, keywords, ex_keywords, weights = utils.process_query_term(term, self.nlp_service)
        ex_kw = utils.get_kv_json(ex_keywords, weights)
        ex_category = self.nlp_service.classify(keywords)
        ex_category = ex_category.get('classify', {})
        ex_category = utils.get_kv_json(ex_category.get('category', []), ex_category.get('category_prob', []))
        ex_category = ex_category[0:MAX_CATEGORY]
        keywords = keywords[0:MAX_KEYWORDS]
        query = self._gen_query(' '.join(keywords), term, filters, order, from_, size_, highlight)
        return query, {}, {'keywords': keywords, 'order': order, 'ex_keywords': ex_kw, "ex_category": ex_category}

    def _build_result(self, es_result, param):
        keywords = param['keywords']
        total = es_result['hits']['total']
        daren = []

        for hit in es_result['hits']['hits']:
            daren.append(self.extract_result(hit))

        return {
            'total': total,
            'keywords': keywords,
            'daren': daren,
            'ex_keywords': param.get('ex_keywords', []),
            'ex_category': param.get('ex_category', [])
        }

    def _gen_query(self, query_keywords, term, filters, order, from_, size_, highlight):
        filter_clause = []
        if filters:
            filter_clause = self._add_filter_match(filter_clause, filters, 'user_id')
            filter_clause = self._add_filter_match(filter_clause, filters, 'user_name')
            filter_clause = self._add_filter_match(filter_clause, filters, 'user_info')
            filter_clause = self._add_filter_match(filter_clause, filters, 'channel_names')
            filter_clause = self._add_filter_match(filter_clause, filters, 'category')
            filter_clause = self._add_filter_match(filter_clause, filters, 'cer_name')

        query = {"query": {"bool": {}}}
        if filter_clause:
            query['query']['bool']['filter'] = filter_clause

        if query_keywords.strip() or term.strip():
            query['query']['bool']['must'] = {
                'bool': {
                    'should': [
                        {
                            'match_phrase': {
                                'user_name': {
                                    'query': term.strip()[0:MAX_CHARACTER],
                                    'slop': 2,
                                    'boost': 3,
                                }
                            }
                        },
                        {
                            'match_phrase': {
                                'description': {
                                    'query': term.strip()[0:MAX_CHARACTER],
                                    'slop': 1,
                                    'boost': 1,
                                }
                            }
                        },
                        {
                            'match_phrase': {
                                'user_info': {
                                    'query': term.lower().strip()[0:MAX_CHARACTER],
                                    'slop': 2,
                                    'boost': 2,
                                }
                            }
                        },
                        {
                            'match': {
                                'user_id': {
                                    'analyzer': 'whitespace',
                                    'query': query_keywords,
                                    'boost': 4,
                                    # 'minimum_should_match': MINIMUM_SHOULD_MATCH
                                }
                            }
                        },
                    ]
                }
            }

        query['sort'] = []

        if order == utils.ORDER_INFLUENCE:
            query['sort'] = [
                {'_score': 'desc'}
            ]
        else:
            query['sort'] = [
                {'_score': 'desc'},
                ]

        query['from'] = from_
        query['size'] = size_
        query['track_scores'] = True
        if highlight:
            query['highlight'] = {
                "pre_tags": ["<span class='keyword'>"],
                "post_tags": ["</span>"],
                "fields": {"user_id": {}, "user_name": {}, "user_info": {}}
            }
        else:
            query['highlight'] = {
                "pre_tags": [""],
                "post_tags": [""],
                "fields": {"user_id": {}, "user_name": {}}
            }

        return query

    @staticmethod
    def _add_filter_match(must_clause, filters, key, cond='must'):
        if key in filters:
            if filters[key]:
                clause = []
                must_clause.append({
                    'bool': {cond: clause}
                })
                values = filters[key]
                if isinstance(values, str):
                    values = values.split(' ')
                for fk in values:
                    clause.append({'match': {key: {'query': fk, 'minimum_should_match': MINIMUM_SHOULD_MATCH}}})
        return must_clause

    @staticmethod
    def _add_filter_clause(filter_clause, filters, key, cond='must'):
        if key in filters:
            if filters[key]:
                clause = []
                filter_clause.append({
                    'bool': {
                        cond: clause
                    }
                })
                for fk in filters[key]:
                    clause.append({'term': {key: fk}})
        return filter_clause

    @staticmethod
    def _add_filter_range_clause(filter_clause, filters, key):
        if key in filters:
            if filters[key]:
                clause = []
                filter_clause.append({
                    'bool': {
                        'must': clause
                    }
                })
                fk = filters[key]
                if not isinstance(fk, list) or len(fk) < 1:
                    pass
                else:
                    min_fk = fk[0]
                    if len(fk) >= 2:
                        max_fk = fk[1]
                    else:
                        max_fk = None
                    if min_fk is not None and min_fk != 'null':
                        clause.append({'range': {key: {"gte": min_fk}}})
                    if max_fk is not None and max_fk != 'null':
                        clause.append({'range': {key: {"lte": max_fk}}})
        return filter_clause

    @staticmethod
    def extract_result(hit):
        if not hit.get('_source'):
            return {}
        source_ = dict(hit['_source'])
        user_info = source_['user_info']

        user_id = source_['user_id']
        user_name = source_['user_name']

        highlight = hit.get('highlight')
        if highlight:
            h_kol_name = highlight.get('user_name')
            user_name = user_name if not h_kol_name else h_kol_name[0]
            h_kol_info = highlight.get('user_info')
            user_info = user_info if not h_kol_info else h_kol_info[0]

        content_page_url = 'https://daren.taobao.com/account_page/daren_home.htm?user_id=' + str(user_id)

        cols = [
                'homepage_url',
                'cer_name',
                'channel_names',
                'head_img',
                'category',
                'system_price',
                'offer',
                'identity',
                'gender',
                'live_adv_price_s',
                'price',
                'common_valid',
                'description',
                'invoice',
                'live_valid',
                'back_pic',
                'owner_status',
                'live_adv_price',
                'receive_rate',
                'score',
                'avg_fee',
                'complete_mission',
                'complete_rate',
                'fans_count',
                'cooperate_seller_count',
                'follow_num',
                'live_daren',
                'qr_code',
                'video_num',
                'articles_num'
                ]

        result = dict([(k, source_.get(k)) for k in cols])
        if source_.get('head_img', '')[0:4] != 'http':
            result['head_img'] = 'http:' + source_.get('head_img', '')

        cn = []
        for k in source_.get('channel_names', []):
            cn.append(k.replace("'", ''))
        result['channel_names'] = cn
        result['user_name'] = user_name
        result['user_id'] = user_id
        result['user_info'] = user_info
        result['content_page_url'] = content_page_url
        return result
